package com.example.gfile.service;

import com.example.gfile.entity.ChainFiled;
import com.example.gfile.entity.CustomizeContent;
import com.example.gfile.entity.FileDetail;
import com.example.gfile.entity.FileHead;
import com.example.gfile.entity.FileName;
import com.example.gfile.entity.FileTemplate;
import com.example.gfile.entity.Filed;
import com.example.gfile.random.IRandomData;
import com.example.gfile.util.JsonUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;

@Service
public class FileJsonParseService {

    public FileTemplate parse(String data) {
        Map<String, String> dataMap = JsonUtil.jsonToObject(data, Map.class);
        FileTemplate fileTemplate = new FileTemplate();

        //解析html表单数据
        BiConsumer<Map<String, String>, FileTemplate> consumer = fileGlobConfig()
                //文件名部分
                .andThen(fileName())
                //文件头数据
                .andThen(fileHead())
                //文件头文本域数据
                .andThen(fileCustomText())
                //文件明细数据
                .andThen(fileDetail())
                //文件结尾数据
                .andThen(fileEnd());
        consumer.accept(dataMap, fileTemplate);
        return fileTemplate;
    }


    private BiConsumer<Map<String, String>, FileTemplate> fileGlobConfig() {
        return ((map, fileTemplate) -> {
            String separator = map.get("separator");
            String fileEncoding = map.get("fileEncoding");
            boolean leftAlign = map.containsKey("leftAlign");
            boolean rightAlign = map.containsKey("rightAlign");
            boolean containDetailData = map.containsKey("containDetailData");
            String fileHeadCustomizeSelect = map.get("fileHeadCustomizeSelect");
            String instId = map.get("instId");

            fileTemplate.setSeparator(separator);
            fileTemplate.setFileEncoding(fileEncoding);
            fileTemplate.setLeftAlign(leftAlign);
            fileTemplate.setRightAlign(rightAlign);
            fileTemplate.setContainDetailData(containDetailData);
            fileTemplate.setFileHeadCustomizeSelect(fileHeadCustomizeSelect);
            fileTemplate.setInstId(StringUtils.isEmpty(instId) ? "通用" : instId);
        }
        );
    }

    private BiConsumer<Map<String, String>, FileTemplate> fileName() {
        return ((map, fileTemplate) -> {
            FileName fileName = new FileName();
            String name = map.get("fileName");
            String fileCount = map.get("fileCount");
            String batchNo = map.get("batchNo");
            String fileNameDate = map.get("fileNameDate");
            boolean fileCompressSwitch = map.containsKey("fileCompressSwitch");
            String fileCompressName = map.get("fileCompressName");
            boolean preFileSwitch = map.containsKey("preFileSwitch");
            String preFileNameSuffix = map.get("preFileNameSuffix");
            fileName.setFileName(name);
            fileName.setFileCount(setDefaultVal(fileCount));
            fileName.setBatchNo(batchNo);
            fileName.setFileNameDate(fileNameDate);
            fileName.setFileCompressSwitch(fileCompressSwitch);
            fileName.setFileCompressName(fileCompressName);
            fileName.setPreFileSwitch(preFileSwitch);
            fileName.setPreFileNameSuffix(preFileNameSuffix);
            fileTemplate.setFileName(fileName);
        }
        );
    }

    private BiConsumer<Map<String, String>, FileTemplate> fileCustomText() {
        return ((map, fileTemplate) -> {
            CustomizeContent customizeContent = new CustomizeContent();
            String customizeTextarea = map.get("customizeTextarea");
            customizeContent.setCustomizeTextarea(customizeTextarea);
            fileTemplate.setCustomizeContent(customizeContent);
        }
        );
    }

    private BiConsumer<Map<String, String>, FileTemplate> fileHead() {
        return ((map, fileTemplate) -> {
            FileHead fileHandler = new FileHead();
            int filedCount = setDefaultVal(map.get("fileHeadCount"));
            boolean headSeparatorEnd = map.containsKey("headSeparatorEnd");

            List<Filed> filedList = new ArrayList<>(filedCount);
            for (int i = 0; i < filedCount; i++) {
                Filed filed = new Filed();
                String type = map.get("headRandomData-" + i);
                String length = map.get("headFiledLength-" + i);
                String content = map.get("filedHeadContent-" + i);
                String affix = map.get("filedHeadAffix-" + i);
                String amount = map.get("chainAmount-" + i);
                String scale = map.get("headAmountNumber-" + i);
                String date = map.get("headFiledDate-" + i);
                filed.setType(type);
                filed.setContent(content);
                int dataLength = setDefaultVal(length);
                filed.setLength(dataLength);
                filed.setAffix(affix);
                int dataAmount = setDefaultVal(amount);
                filed.setAmount(dataAmount);
                int dataScale = setDefaultVal(scale);
                filed.setScale(dataScale);
                filed.setDate(date);
                filedList.add(filed);
            }
            fileHandler.setFiledList(filedList);
            fileHandler.setHeadSeparatorEnd(headSeparatorEnd);
            fileTemplate.setFileHead(fileHandler);
        }
        );
    }

    private int setDefaultVal(String value) {
        if (StringUtils.isEmpty(value)) {
            return 0;
        }
        return Integer.parseInt(value);
    }


    private BiConsumer<Map<String, String>, FileTemplate> fileDetail() {
        return ((map, fileTemplate) -> {
            //明细多阶段内容个数
            int stageCount = setDefaultVal(map.get("stageCount"));
            boolean detailSeparatorEnd = map.containsKey("detailSeparatorEnd");

            //解析多个明细
            List<FileDetail> fileDetailList = new ArrayList<>(stageCount);
            for (int i = 1; i <= stageCount; i++) {
                String data = map.get("multi-detail-" + i);
                Map<String, String> dataMap = JsonUtil.jsonToObject(data, Map.class);
                String fileDetailFiledCount = dataMap.get("fileDetailFiledCount");
                String fileDetailDataCount = dataMap.get("fileDetailDataCount");
                String dbId = dataMap.get("dbId");
                String sql = dataMap.get("sql");
                int detailFiledCount = setDefaultVal(fileDetailFiledCount);
                int detailDataCount = setDefaultVal(fileDetailDataCount);

                FileDetail fileDetail = new FileDetail();
                fileDetail.setFileDetailDataCount(detailDataCount);
                fileDetail.setSql(sql);
                fileDetail.setDbId(dbId);

                //解析明细字段
                List<Filed> filedList = new ArrayList<>(detailFiledCount);
                for (int j = 0; j < detailFiledCount; j++) {
                    Filed filed = new Filed();
                    String type = dataMap.get("detailRandomData-" + j);
                    String length = dataMap.get("detailFiledLength-" + j);
                    String content = dataMap.get("filedDetailContent-" + j);
                    String affix = dataMap.get("filedDetailAffix-" + j);
                    String amount = dataMap.get("detailAmount-" + j);
                    String scale = dataMap.get("detailAmountNumber-" + j);
                    String date = dataMap.get("detailFiledDate-" + j);
                    String filedChainContent = dataMap.get("filedChainContent-" + j);
                    String dbColumn = dataMap.get("dbColumn-" + j);
                    filed.setType(type);
                    filed.setContent(content);
                    int dataLength = setDefaultVal(length);
                    filed.setLength(dataLength);
                    filed.setAffix(affix);
                    int dataAmount = setDefaultVal(amount);
                    filed.setAmount(dataAmount);
                    int dataScale = setDefaultVal(scale);
                    filed.setScale(dataScale);
                    if (IRandomData.LIST_TYPE.equals(type)) {
                        ChainFiled chainFiled = fileDetailChain(filedChainContent);
                        filed.setChainFiled(chainFiled);
                    }
                    filed.setDate(date);
                    filed.setColumn(dbColumn);
                    filed.setSqlId(String.valueOf(i - 1));
                    filedList.add(filed);
                }
                fileDetail.setFiledList(filedList);
                fileDetailList.add(fileDetail);
            }

            fileTemplate.setDetailSeparatorEnd(detailSeparatorEnd);
            fileTemplate.setFileDetailList(fileDetailList);
        }
        );
    }

    private ChainFiled fileDetailChain(String filedChainContent) {
        if (StringUtils.isEmpty(filedChainContent)) {
            return new ChainFiled();
        }

        ChainFiled chainFiled = new ChainFiled();
        Map<String, String> map = JsonUtil.jsonToObject(filedChainContent, Map.class);
        String chainCollCount = map.get("chainCollCount");
        String chainCollElementCount = map.get("chainCollElementCount");
        String chainCollElementSeparator = map.get("chainCollElementSeparator");
        String chainCollPrefix = map.get("chainCollPrefix");
        String chainCollSuffix = map.get("chainCollSuffix");
        String chainPrefix = map.get("chainPrefix");
        String chainSuffix = map.get("chainSuffix");
        String chainFiledSeparator = map.get("chainFiledSeparator");
        chainFiled.setCollPrefix(chainCollPrefix);
        chainFiled.setCollSuffix(chainCollSuffix);
        chainFiled.setChainPrefix(chainPrefix);
        chainFiled.setChainSuffix(chainSuffix);
        chainFiled.setSeparator(chainFiledSeparator);
        int filedCount = setDefaultVal(chainCollCount);
        int collElementCount = setDefaultVal(chainCollElementCount);
        chainFiled.setCollElementCount(collElementCount);
        chainFiled.setCollCount(filedCount);
        chainFiled.setCollElementSeparator(chainCollElementSeparator);

        List<Filed> filedList = new ArrayList<>(filedCount);
        for (int i = 0; i < filedCount; i++) {
            Filed filed = new Filed();
            String type = map.get("chainRandomData-" + i);
            String length = map.get("chainFiledLength-" + i);
            String content = map.get("filedChainContent-" + i);
            String affix = map.get("filedChainAffix-" + i);
            String amount = map.get("chainAmount-" + i);
            String scale = map.get("chainAmountNumber-" + i);
            String date = map.get("chainFiledDate-" + i);
            filed.setType(type);
            filed.setContent(content);
            int dataLength = setDefaultVal(length);
            filed.setLength(dataLength);
            filed.setAffix(affix);
            int dataAmount = setDefaultVal(amount);
            filed.setAmount(dataAmount);
            int dataScale = setDefaultVal(scale);
            filed.setScale(dataScale);
            filed.setDate(date);
            filedList.add(filed);
        }
        chainFiled.setChainFiledList(filedList);
        return chainFiled;
    }

    private BiConsumer<Map<String, String>, FileTemplate> fileEnd() {
        return ((map, fileTemplate) -> {
            String endTextarea = map.get("endTextarea");
            fileTemplate.setEndTextarea(endTextarea);
        });
    }
}
